import re
from math import ceil

from fastapi import APIRouter
from re_common.baselibrary.tools.all_requests.aiohttp_request import AioHttpRequest
from re_common.baselibrary.tools.myparsel import MParsel
from re_common.baselibrary.utils.basedict import BaseDicts
from re_common.baselibrary.utils.baseurl import BaseUrl
from re_common.baselibrary.utils.core.mlamada import bools_string

from apps.allsubdb.cnkijournal.models import VerificationRef, VerificationArticle
from apps.core.callback import default_call_back
from apps.core.global_model import ParseHtmlModel, MHtmlModel
from apps.core.m_route import ContextIncludedRoute
from apps.core.return_info import ReturnInfo, InputInfoModel, SUCCESS, FAILED

router = APIRouter(route_class=ContextIncludedRoute)


@router.post("/step1/parse_journal_home")
async def parse_article(input: InputInfoModel[ParseHtmlModel]):
    """
    解析信息用于下载ref rel等
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    html = input.data.html
    css_dicts = {
        # 期刊量
        'class_info': {
            'parent': 'a',
            'children': {
                'text': 'a > em::text',
                'onclick': 'a::attr(onclick)',
            }
        }
    }
    mc = MParsel(html=html)
    new_dict = mc.css_parsel(sel=mc.sel, css_selector=css_dicts)
    BaseDicts.get_recursive_dict(new_dict, None, default_call_back)
    lists = []
    for item in new_dict["class_info"]["children"]:
        count = item["text"].replace("(", "").replace(")", "")
        onclick = item["onclick"]
        sub = re.findall("Submit.naviSearch\('1','168专题代码','(.*?)','(.*?)'\)", onclick)
        if sub:
            new_dict2 = {}
            code = sub[0][0]
            name = sub[0][1]
            new_dict2["code"] = code
            new_dict2["name"] = name
            new_dict2["count"] = count
            lists.append(new_dict2)

    return_info.status = bools_string(True)
    return_info.msg_code = 200
    return_info.msg = ""
    return_info.data = lists
    return return_info.todict()


@router.post("/step1/parse_journal_id")
async def parse_article(input: InputInfoModel[ParseHtmlModel]):
    """
    解析信息用于下载ref rel等
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    html = input.data.html
    css_dicts = {
        # 期刊量
        'lblCount': 'em[class="lblCount"]::text',
        'lblPageCount': 'em[id="lblPageCount"]::text',
        'qkinfo': {
            'parent': 'ul[class="list_tab"] > li',
            'children': {
                'qkname': 'a::text',
                'pykm': 'a::attr(href)',
                'organSpan': 'span[class="tab_2"]::text',  # 主办单位
                'fhfactorSpan': 'span[class="tab_3"]::text',  # 复合影响因子
                'zhfactorSpan': 'span[class="tab_4"]::text',  # 综合影响因子
                'bztimes': 'span[class="tab_5"]::text',  # 被引次数
                'flag': 'div[class="flag"] *::text'  # 发行方式
            }
        }
    }

    def call_back(key, value):
        result = ""
        if isinstance(value, list):
            for val in value:
                val = val.replace("\r", "").replace("\n", "").strip()
                if val != "":
                    result = result + val + ";"
        else:
            result = value
        result = result.rstrip(";")
        if key == "pykm":
            result_raw = result
            result = BaseUrl.urlQuery2Dict(result)
            if isinstance(result, dict) and "baseid" in result.keys():
                result = result["baseid"]
            elif result_raw.find("index"):
                result = result_raw.split("/")[-1]
            else:
                result = ""
        return result

    mc = MParsel(html=html)
    new_dict = mc.css_parsel(sel=mc.sel, css_selector=css_dicts)
    BaseDicts.get_recursive_dict(new_dict, None, call_back)
    return_info.status = bools_string(True)
    return_info.msg_code = 200
    return_info.msg = ""
    return_info.data = {"result": new_dict}
    return return_info.todict()


@router.post("/step2/parse_journal_info")
async def parse_issue(input: InputInfoModel[ParseHtmlModel]):
    """
    解析独立的期刊信息
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    html = input.data.html
    # lxml bug 导致 不能获取h3下的p标签
    from bs4 import BeautifulSoup
    soup = BeautifulSoup(html, 'html.parser')
    tag = soup.h3.p
    tag.name = "em"
    html = soup.prettify()

    css_dicts = {
        'qk_name_alt': 'h3 > em::text',
        'cnki_exclusive': 'b[class="icon-unique"]::text',
        'individual_issue': 'span[class="icon-issue"]::text',
        'first_launch': 'span[class="pic-first"]::text',
        'evaluate_info': 'ul[id="evaluateInfo"] *::text',
        'qk_info': {
            'parent': 'div[class="listbox clearfix"] > ul > li > p',
            'children': {
                'key_name': 'p::text',
                'value': 'p > span::text'
            }
        }
    }

    def call_back(key, value):
        """
        默认的解析回调
        :param key:
        :param value:
        :return:
        """
        result = ""
        if isinstance(value, list):
            for val in value:
                val = val.replace("\r", "").replace("\n", "").strip()
                if val != "":
                    result = result + val + ";"
        else:
            result = value
        result = result.rstrip(";")
        if key == "evaluate_info":
            result = result.replace(";", "").replace("评价信息", "").strip()
        if key in ["cnki_exclusive", "individual_issue", "first_launch"]:
            if result == "":
                result = 0
            else:
                result = 1
        return result

    mc = MParsel(html=html)
    new_dict = mc.css_parsel(sel=mc.sel, css_selector=css_dicts)
    BaseDicts.get_recursive_dict(new_dict, None, call_back)
    return_info.status = bools_string(True)
    return_info.msg_code = 200
    return_info.msg = ""
    return_info.data = new_dict
    return return_info.todict()


@router.post("/step5/parse_year")
async def parse_issue(input: InputInfoModel[ParseHtmlModel]):
    """
    解析下载的期，解析出文章的id
    :return:
    """
    return_info = ReturnInfo()
    html = input.data.html
    css_dicts = {
        "year_issue": {
            'parent': 'div[class="yearissuepage"] > dl[class~="s-dataList"]',
            'children': {
                "year": 'dt > em::text',
                "issue": 'dd > a::text'
            }
        }
    }
    mc = MParsel(html=html)
    new_dict = mc.css_parsel(sel=mc.sel, css_selector=css_dicts)
    BaseDicts.get_recursive_dict(new_dict, None, default_call_back)
    return_info.status = bools_string(True)
    return_info.msg_code = 200
    return_info.msg = ""
    return_info.data = new_dict
    return return_info.todict()


@router.post("/step5/parse_online")
async def parse_issue(input: InputInfoModel[ParseHtmlModel]):
    """
    解析下载的期，解析出文章的id
    :return:
    """
    return_info = ReturnInfo()
    html = input.data.html
    css_dicts = {
        "input": 'input[id="articleCount"]::attr(value)',
        "article": {
            'parent': 'dd',
            'children': {
                "title": 'span[class="name"] > a::text',
                "href": 'span[class="name"] > a::attr(href)',
                "times": 'span[class="company"]::text',
            }
        }
    }
    mc = MParsel(html=html)
    new_dict = mc.css_parsel(sel=mc.sel, css_selector=css_dicts)
    BaseDicts.get_recursive_dict(new_dict, None, default_call_back)
    input = new_dict["input"]
    lists = []
    for item in new_dict["article"]["children"]:
        url = item["href"]
        dictss = BaseUrl.urlQuery2Dict(url)
        ids = dictss["url"]
        filename = dictss["filename"]
        item["href"] = ids
        item["filename"] = filename
        lists.append(item)

    return_info.status = bools_string(True)
    return_info.msg_code = 200
    return_info.msg = ""
    return_info.data = {"input": input, "lists": lists}
    return return_info.todict()


@router.post("/step7/parse_issue")
async def parse_issue(input: InputInfoModel[ParseHtmlModel]):
    return_info = ReturnInfo()
    html = input.data.html
    css_dicts = {
        'articleCount': 'input[id="articleCount"]::attr(value)',
        "issue_info": {
            'parent': 'dt',
            'children': {
                'parent': 'dt ~ dd',
                'col': 'dt::text',
                'children': {
                    'url': 'dd > span[class="name"] > a::attr(href)',
                    'title': 'dd > span[class="name"] > a::text',
                    'pageline': 'dd > span[class="company"]::text',
                    'if_html_fulltext': 'li[class="btn-view"] > a > b::attr(title) ',

                }

            }
        }
    }
    mc = MParsel(html=html)
    new_dict = mc.css_parsel(sel=mc.sel, css_selector=css_dicts)
    BaseDicts.get_recursive_dict(new_dict, None, default_call_back)
    return_info.status = bools_string(True)
    return_info.msg_code = 200
    return_info.msg = ""
    return_info.data = new_dict
    return return_info.todict()


@router.post("/step8/parse_article_down_relref")
async def parse_article(input: InputInfoModel[ParseHtmlModel]):
    """
    解析信息用于下载ref rel等
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    html = input.data.html
    css_dicts = {
        'uid': 'input[id="loginuserid"]::attr(value)',
        'vl': 'input[id="listv"]::attr(value)',
        'dbname': 'input[id="paramdbname"]::attr(value)',
        'filename': 'input[id="paramfilename"]::attr(value)',
        'dbcode': 'input[id="paramdbcode"]::attr(value)',
    }

    mc = MParsel(html=html)
    new_dict = mc.css_parsel(sel=mc.sel, css_selector=css_dicts)
    BaseDicts.get_recursive_dict(new_dict, None, default_call_back)
    return_info.status = bools_string(True)
    return_info.msg_code = 200
    return_info.msg = ""
    return_info.data = {"ref": new_dict}
    return return_info.todict()


@router.post("/step8/parse_ref_downpage")
async def parse_article(input: InputInfoModel[VerificationRef]):
    """
    解析ref 得到要需要的翻页信息
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    html = input.data.html
    refcount = input.data.refcount
    xpath_dicts = {
        'showpage': '//div[@class="pageBar"]//text()',
        'pcount': '//span[@name="pcount"]/text()'
    }

    def call_back(key, value):
        """
        默认的解析回调
        :param key:
        :param value:
        :return:
        """
        result = ""
        if isinstance(value, list):
            for val in value:
                val = val.replace("\r", "").replace("\n", "").strip()
                if val != "":
                    result = result + val + ";"
        else:
            result = value
        result = result.rstrip(";")

        if key == "showpage":
            dicts = {}
            for item in result.split(";"):
                matObj = re.search(r"ShowPage\('(\d+)','([^']+)',", item)
                if not matObj:
                    continue
                pageTotal = ceil(int(matObj.group(1)) / 10)
                CurDBCode = matObj.group(2)
                for i in range(2, pageTotal + 1):
                    dicts[CurDBCode + "_" + str(i)] = ""
            result = dicts
        if key == "pcount":
            allcount = 0
            for item in result.split(";"):
                allcount = allcount + int(item)
            result = allcount
        return result

    mc = MParsel(html=html)
    new_dict = mc.xpath_parsel(sel=mc.sel, xpath_selector=xpath_dicts)
    BaseDicts.get_recursive_dict(new_dict, None, call_back)
    if new_dict["pcount"] == refcount:
        new_dict["ver_ref_count"] = "true"
    else:
        new_dict["ver_ref_count"] = "false"
    return_info.status = SUCCESS
    return_info.msg_code = 200
    return_info.msg = ""
    return_info.data = new_dict
    return return_info.todict()


@router.post("/step10/parse_cited_page")
async def parse_article(input: InputInfoModel[MHtmlModel]):
    """
    解析ref 得到要需要的翻页信息
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    html_list = input.data.html_list
    ids = input.data.id

    def call_back(key, value):
        """
        默认的解析回调
        :param key:
        :param value:
        :return:
        """
        result = ""
        if isinstance(value, list):
            for val in value:
                val = val.replace("\r", "").replace("\n", "").strip()
                if val != "":
                    result = result + val + ";"
        else:
            result = value
        result = result.rstrip(";")

        if key == "id":
            if result:
                result = BaseUrl.urlQuery2Dict(result)["filename"]
        if key == "id2":
            if result:
                result = result.split("!")[1]
        return result

    result_list = []
    for html in html_list:
        xpath_dicts = {
            'parent': '//body/div[@class="essayBox"]/ul/li',
            'children': {
                "text": ".//text()",
                "id": "./a/@href",
                "id2": "./input/@value"
            }
        }

        mc = MParsel(html=html)
        new_dict = mc.xpath_parsel(sel=mc.sel, xpath_selector=xpath_dicts)
        BaseDicts.get_recursive_dict(new_dict, None, call_back)
        result_list.extend(new_dict["children"])
    result_dicts = {}
    for item in result_list:
        sets = set()
        if item["id"]:
            sets.add(item["id"])
        if item["id2"]:
            sets.add(item["id2"])

        types = re.findall(r';\[([A-Z]+)]', item["text"])
        types = "".join(types)
        result_dicts[";".join(sets)] = {
            "text": item["text"],
            "type": types
        }

    return_info.status = SUCCESS
    return_info.msg_code = 200
    return_info.msg = ""
    return_info.data = {"article_id": ids, "cited_dicts": result_dicts}
    return return_info.todict()


@router.post("/verification/ver_article")
def verification_ref(input: InputInfoModel[VerificationArticle]):
    """
    验证article 是否正确
    :param input:
    :return:
    """
    return_info = ReturnInfo()
    marks = input.data.marks
    html = input.data.html
    rrq = AioHttpRequest()
    rrq.set_marks(marks).set_html(html)
    bools, dicts = rrq.all_middlerwares({})
    if bools:
        return_info.status = SUCCESS
        return_info.msg_code = 200
        return_info.msg = ""
        return_info.data = ""
    else:
        return_info.status = FAILED
        return_info.msg_code = 200
        return_info.msg = ""
        return_info.data = ""
